tuviv 0.2.1

A TUI library focused on layout
Documentation

Tuviv

Tuviv is a library for building terminal user interfaces (TUIs) with rust with a heavy focus on layout. Tuviv does not come with as many widgets as, say, tui-rs, but rather contains many more widgets based on layout: specifically a Flexbox, and a Grid, along with others.

The purpose of this library is to significantly ease creating layouts, which is mildly clunky with tui-rs: such as the fact that you cannot center text vertically (#396) - but also wider-scale things - such as the lack of a flexbox or a grid.

Examples

Create a Buffer And Render a Widget

use std::io::{self, stdout, Write};
use crossterm::{cursor, event::DisableMouseCapture,
    execute,
    terminal::{
        self, disable_raw_mode, enable_raw_mode, EnterAlternateScreen,
        LeaveAlternateScreen,
    },
};
use tuviv::{layout::{Rect, Vec2}, CrosstermBackend, Widget};

fn main() -> io::Result<()> {

    // Prepare the stdout for printing a tui
    let mut stdout = stdout();
    execute!(stdout, EnterAlternateScreen, cursor::Hide)?;
    enable_raw_mode()?;

    let p = Paragraph::new("HI");

    loop {
        // Get the size of the terminal
        let size = terminal::size()?;

        // Create the buffer to write to
        let backend = CrosstermBackend;
        let mut buffer =
            tuviv::Buffer::new(Vec2::new(size.0.into(), size.1.into()));

        // Render the widget onto the buffer.
        p.render(Rect::new(0, 0, size.0.into(), size.1.into()), &mut buffer);

        // Render the buffer to the terminal
        backend.finish(&buffer, &mut stdout)?;
    }

    // Restore terminal
    disable_raw_mode()?;
    execute!(stdout, LeaveAlternateScreen, DisableMouseCapture, cursor::Show)?;

    Ok(())
}

Create More Complicated Widget Trees

Tuviv uses a builder pattern so more complicated widgets can be created easily:

use tuviv::prelude::*;

// Create a grid with progressbars:
//
// ╭───────────────╮
// │CPU  █▌────────│
// │MEM  ███▌──────│
// │GPU  ─────CO o │
// ╰───────────────╯
let grid = Grid::new()
    .template_rows(vec![Sizing::Auto; 3])
    .template_columns(vec![Sizing::Auto, Sizing::AutoFixed(10)])
    .column_gap(2)
    .auto_child(Paragraph::new("CPU".styled()))
    .auto_child(
        ProgressBar::new()
            .total(100.0)
            .value(10.0)
            .align_y(Alignment::Center),
    )
    .auto_child(Paragraph::new("MEM".styled()))
    .auto_child(
        ProgressBar::new()
            .total(8.0)
            .value(2.4)
            .align_y(Alignment::Center),
    )
    .auto_child(Paragraph::new("GPU".styled()))
    .auto_child(
        ProgressBar::new()
            .total(15.0)
            .value(8.0)
            .fg(vec!["".styled().bold()])
            .edge("C".styled().yellow().bold())
            .bg(vec!["O o ".styled()])
            .align_y(Alignment::Center),
    )
    .to_box_sizing()
    .border(Border::ROUNDED)
    .centered();